package com.xian.tszs.utils;

import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Calendar;
import java.util.Date;
import java.util.List;

/**
 * 日期工具类
 * @author Fujing
 * @date 2019年2月22日 下午3:50:15
 *
 */
public class DateUtils {

	/**
	 * 常用变量
	 */
	public static final String DATE_FORMAT_FULL = "yyyy-MM-dd HH:mm:ss";
	public static final String DATE_FORMAT_YMD = "yyyy-MM-dd";
	public static final String DATE_FORMAT_HMS = "HH:mm:ss";
	public static final String DATE_FORMAT_HM = "HH:mm";
	public static final String DATE_FORMAT_YMDHM = "yyyy-MM-dd HH:mm";
	public static final String DATE_FORMAT_YMDHMS = "yyyyMMddHHmmss";
	public static final long ONE_DAY_MILLS = 3600000 * 24;
	public static final int WEEK_DAYS = 7;
	private static final int dateLength = DATE_FORMAT_YMDHM.length();
	
	/**
	 * 返回当前时间相差n个小时的时间
	 * @author Fujing
	 * @date 2019年4月6日 下午3:05:04
	 * @param n
	 * @return String
	 */
	public static String getHourFromCurrent(int n){
		Calendar calen = Calendar.getInstance();//可以对每个时间域单独修改
		calen.setTime(new Date());
		calen.set(Calendar.HOUR_OF_DAY, calen.get(Calendar.HOUR_OF_DAY) + n);
		SimpleDateFormat format = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
		String time = format.format(calen.getTime());
		return time;
	}

	/**
	 * 日期转换为制定格式字符串
	 * 
	 * @param time
	 * @param format
	 * @return
	 */
	public static String formatDateToString(Date time, String format) {
		SimpleDateFormat sdf = new SimpleDateFormat(format);
		return sdf.format(time);
	}

	/**
	 * 字符串转换为制定格式日期 (注意：当你输入的日期是2014-12-21 12:12，format对应的应为yyyy-MM-dd HH:mm
	 * 否则异常抛出)
	 * 
	 * @param date
	 * @param format
	 * @return
	 * @throws ParseException
	 * @
	 */
	public static Date formatStringToDate(String date, String format) {
		SimpleDateFormat sdf = new SimpleDateFormat(format);
		try {
			return sdf.parse(date);
		} catch (ParseException ex) {
			ex.printStackTrace();
			throw new RuntimeException(ex.toString());
		}
	}

	/**
	 * 判断一个日期是否属于两个时段内
	 * 
	 * @param time
	 * @param timeRange
	 * @return
	 */
	public static boolean isTimeInRange(Date time, Date[] timeRange) {
		return (!time.before(timeRange[0]) && !time.after(timeRange[1]));
	}

	/**
	 * 从完整的时间截取精确到分的时间
	 * 
	 * @param fullDateStr
	 * @return
	 */
	public static String getDateToMinute(String fullDateStr) {
		return fullDateStr == null ? null
				: (fullDateStr.length() >= dateLength ? fullDateStr.substring(0, dateLength) : fullDateStr);
	}

	/**
	 * 返回指定年度的所有周。List中包含的是String[2]对象 string[0]本周的开始日期,string[1]是本周的结束日期。
	 * 日期的格式为YYYY-MM-DD 每年的第一个周，必须包含星期一且是完整的七天。
	 * 例如：2009年的第一个周开始日期为2009-01-05，结束日期为2009-01-11。 星期一在哪一年，那么包含这个星期的周就是哪一年的周。
	 * 例如：2008-12-29是星期一，2009-01-04是星期日，哪么这个周就是2008年度的最后一个周。
	 * 
	 * @param year
	 *            格式 YYYY ，必须大于1900年度 小于9999年
	 * @return @
	 */
	public static List<String[]> getWeeksByYear(final int year) {
		int weeks = getWeekNumOfYear(year);
		List<String[]> result = new ArrayList<String[]>(weeks);
		int start = 1;
		int end = 7;
		for (int i = 1; i <= weeks; i++) {
			String[] tempWeek = new String[2];
			tempWeek[0] = getDateForDayOfWeek(year, i, start);
			tempWeek[1] = getDateForDayOfWeek(year, i, end);
			result.add(tempWeek);
		}
		return result;
	}
	
	/**
	 * 获取本周的第一天
	 * @return String
	 * **/
	public static String getWeekStart(){
		Calendar cal=Calendar.getInstance();
		cal.add(Calendar.WEEK_OF_MONTH, 0);
		cal.set(Calendar.DAY_OF_WEEK, 2);
		Date time=cal.getTime();
		return new SimpleDateFormat("yyyy-MM-dd").format(time);
	}
	/**
	 * 获取本周的最后一天
	 * @return String
	 * **/
	public static String getWeekEnd(){
		Calendar cal=Calendar.getInstance();
		cal.set(Calendar.DAY_OF_WEEK, cal.getActualMaximum(Calendar.DAY_OF_WEEK));
		cal.add(Calendar.DAY_OF_WEEK, 1);
		Date time=cal.getTime();
		return new SimpleDateFormat("yyyy-MM-dd").format(time);
	}


	/**
	 * 计算指定年、周的上一年、周
	 * 
	 * @param year
	 * @param week
	 * @return @
	 */
	public static int[] getLastYearWeek(int year, int week) {
		if (week <= 0) {
			throw new IllegalArgumentException("周序号不能小于1！！");
		}
		int[] result = { week, year };
		if (week == 1) {
			// 上一年
			result[1] -= 1;
			// 最后一周
			result[0] = getWeekNumOfYear(result[1]);
		} else {
			result[0] -= 1;
		}
		return result;
	}

	/**
	 * 下一个[周，年]
	 * 
	 * @param year
	 * @param week
	 * @return @
	 */
	public static int[] getNextYearWeek(int year, int week) {
		if (week <= 0) {
			throw new IllegalArgumentException("周序号不能小于1！！");
		}
		int[] result = { week, year };
		int weeks = getWeekNumOfYear(year);
		if (week == weeks) {
			// 下一年
			result[1] += 1;
			// 第一周
			result[0] = 1;
		} else {
			result[0] += 1;
		}
		return result;
	}

	/**
	 * 计算指定年度共有多少个周。(从周一开始)
	 * 
	 * @param year
	 * @return @
	 */
	public static int getWeekNumOfYear(final int year) {
		return getWeekNumOfYear(year, Calendar.MONDAY);
	}

	/**
	 * 计算指定年度共有多少个周。
	 * 
	 * @param year
	 *            yyyy
	 * @return @
	 */
	public static int getWeekNumOfYear(final int year, int firstDayOfWeek) {
		// 每年至少有52个周 ，最多有53个周。
		int minWeeks = 52;
		int maxWeeks = 53;
		int result = minWeeks;
		int sIndex = 4;
		String date = getDateForDayOfWeek(year, maxWeeks, firstDayOfWeek);
		// 判断年度是否相符，如果相符说明有53个周。
		if (date.substring(0, sIndex).equals(year)) {
			result = maxWeeks;
		}
		return result;
	}

	public static int getWeeksOfWeekYear(final int year) {
		Calendar cal = Calendar.getInstance();
		cal.setFirstDayOfWeek(Calendar.MONDAY);
		cal.setMinimalDaysInFirstWeek(WEEK_DAYS);
		cal.set(Calendar.YEAR, year);
		return cal.getWeeksInWeekYear();
	}

	/**
	 * 获取指定年份的第几周的第几天对应的日期yyyy-MM-dd(从周一开始)
	 * 
	 * @param year
	 * @param weekOfYear
	 * @param dayOfWeek
	 * @return yyyy-MM-dd 格式的日期 @
	 */
	public static String getDateForDayOfWeek(int year, int weekOfYear, int dayOfWeek) {
		return getDateForDayOfWeek(year, weekOfYear, dayOfWeek, Calendar.MONDAY);
	}

	/**
	 * 获取指定年份的第几周的第几天对应的日期yyyy-MM-dd，指定周几算一周的第一天（firstDayOfWeek）
	 * 
	 * @param year
	 * @param weekOfYear
	 * @param dayOfWeek
	 * @param firstDayOfWeek
	 *            指定周几算一周的第一天
	 * @return yyyy-MM-dd 格式的日期
	 */
	public static String getDateForDayOfWeek(int year, int weekOfYear, int dayOfWeek, int firstDayOfWeek) {
		Calendar cal = Calendar.getInstance();
		cal.setFirstDayOfWeek(firstDayOfWeek);
		cal.set(Calendar.DAY_OF_WEEK, dayOfWeek);
		cal.setMinimalDaysInFirstWeek(WEEK_DAYS);
		cal.set(Calendar.YEAR, year);
		cal.set(Calendar.WEEK_OF_YEAR, weekOfYear);
		return formatDateToString(cal.getTime(), DATE_FORMAT_YMD);
	}

	/**
	 * 获取指定日期星期几
	 * 
	 * @param datetime
	 * @throws ParseException
	 * @
	 */
	public static int getWeekOfDate(String datetime) throws ParseException {
		Calendar cal = Calendar.getInstance();
		cal.setFirstDayOfWeek(Calendar.MONDAY);
		cal.setMinimalDaysInFirstWeek(WEEK_DAYS);
		Date date = formatStringToDate(datetime, DATE_FORMAT_YMD);
		cal.setTime(date);
		return cal.get(Calendar.DAY_OF_WEEK);

	}

	/**
	 * 计算某年某周内的所有日期(从周一开始 为每周的第一天)
	 * 
	 * @param yearNum
	 * @param weekNum
	 * @return @
	 */
	public static List<String> getWeekDays(int yearNum, int weekNum) {
		return getWeekDays(yearNum, weekNum, Calendar.MONDAY);
	}

	/**
	 * 计算某年某周内的所有日期(七天)
	 * 
	 * @param yearNum
	 * @param weekNum
	 * @return yyyy-MM-dd 格式的日期列表
	 */
	public static List<String> getWeekDays(int year, int weekOfYear, int firstDayOfWeek) {
		List<String> dates = new ArrayList<String>();
		int dayOfWeek = firstDayOfWeek;
		for (int i = 0; i < WEEK_DAYS; i++) {
			dates.add(getDateForDayOfWeek(year, weekOfYear, dayOfWeek++, firstDayOfWeek));
		}
		return dates;
	}

	/**
	 * 获取目标日期的上周、或本周、或下周的年、周信息
	 * 
	 * @param queryDate
	 *            传入的时间
	 * @param weekOffset
	 *            -1:上周 0:本周 1:下周
	 * @param firstDayOfWeek
	 *            每周以第几天为首日
	 * @return
	 * @throws ParseException
	 */
	public static int[] getWeekAndYear(String queryDate, int weekOffset, int firstDayOfWeek) throws ParseException {

		Date date = formatStringToDate(queryDate, DATE_FORMAT_YMD);
		Calendar calendar = Calendar.getInstance();
		calendar.setTime(date);
		calendar.setFirstDayOfWeek(firstDayOfWeek);
		calendar.setMinimalDaysInFirstWeek(WEEK_DAYS);
		int year = calendar.getWeekYear();
		int week = calendar.get(Calendar.WEEK_OF_YEAR);
		int[] result = { week, year };
		switch (weekOffset) {
		case 1:
			result = getNextYearWeek(year, week);
			break;
		case -1:
			result = getLastYearWeek(year, week);
			break;
		default:
			break;
		}
		return result;
	}

	/**
	 * 计算个两日期的天数
	 * 
	 * @param startDate
	 *            开始日期字串
	 * @param endDate
	 *            结束日期字串
	 * @return
	 * @throws ParseException
	 */
	public static int getDaysBetween(String startDate, String endDate) throws ParseException {
		int dayGap = 0;
		if (startDate != null && startDate.length() > 0 && endDate != null && endDate.length() > 0) {
			Date end = formatStringToDate(endDate, DATE_FORMAT_YMD);
			Date start = formatStringToDate(startDate, DATE_FORMAT_YMD);
			dayGap = getDaysBetween(start, end);
		}
		return dayGap;
	}
	
	public static int getDaysBetween(Date startDate, Date endDate) {
		return (int) ((endDate.getTime() - startDate.getTime()) / ONE_DAY_MILLS);
	}

	/**
	 * 计算两个日期之间的天数差
	 * 
	 * @param startDate
	 * @param endDate
	 * @return
	 */
	public static int getDaysGapOfDates(Date startDate, Date endDate) {
		int date = 0;
		if (startDate != null && endDate != null) {
			date = getDaysBetween(startDate, endDate);
		}
		return date;
	}

	/**
	 * 计算两个日期之间的年份差距
	 * 
	 * @param firstDate
	 * @param secondDate
	 * @return
	 */

	public static int getYearGapOfDates(Date firstDate, Date secondDate) {
		if (firstDate == null || secondDate == null) {
			return 0;
		}
		Calendar helpCalendar = Calendar.getInstance();
		helpCalendar.setTime(firstDate);
		int firstYear = helpCalendar.get(Calendar.YEAR);
		helpCalendar.setTime(secondDate);
		int secondYear = helpCalendar.get(Calendar.YEAR);
		return secondYear - firstYear;
	}

	/**
	 * 计算两个日期之间的月份差距
	 * 
	 * @param firstDate
	 * @param secondDate
	 * @return
	 */
	public static int getMonthGapOfDates(Date firstDate, Date secondDate) {
		if (firstDate == null || secondDate == null) {
			return 0;
		}

		return (int) ((secondDate.getTime() - firstDate.getTime()) / ONE_DAY_MILLS / 30);

	}

	/**
	 * 计算是否包含当前日期
	 * 
	 * @param datys
	 * @return
	 */
	public static boolean isContainCurrent(List<String> dates) {
		boolean flag = false;
		SimpleDateFormat fmt = new SimpleDateFormat(DATE_FORMAT_YMD);
		Date date = new Date();
		String dateStr = fmt.format(date);
		for (int i = 0; i < dates.size(); i++) {
			if (dateStr.equals(dates.get(i))) {
				flag = true;
			}
		}
		return flag;
	}

	/**
	 * 从date开始计算time天后的日期
	 * 
	 * @param date
	 * @param time
	 * @return
	 * @throws ParseException
	 */
	public static String getCalculateDateToString(String startDate, int time) throws ParseException {
		String resultDate = null;
		if (startDate != null && startDate.length() > 0) {
			Date date = formatStringToDate(startDate, DATE_FORMAT_YMD);
			Calendar c = Calendar.getInstance();
			c.setTime(date);
			c.set(Calendar.DAY_OF_YEAR, time);
			date = c.getTime();
			resultDate = formatDateToString(date, DATE_FORMAT_YMD);
		}
		return resultDate;
	}

	/**
	 * 获取从某日期开始计算，指定的日期所在该年的第几周
	 * 
	 * @param date
	 * @param admitDate
	 * @return
	 * @throws ParseException
	 * @
	 */
	public static int[] getYearAndWeeks(String date, String admitDate) throws ParseException {
		Calendar c = Calendar.getInstance();
		c.setTime(formatStringToDate(admitDate, DATE_FORMAT_YMD));
		int time = c.get(Calendar.DAY_OF_WEEK);
		return getWeekAndYear(date, 0, time);
	}

	/**
	 * 获取指定日期refDate，前或后一周的所有日期
	 * 
	 * @param refDate
	 *            参考日期
	 * @param weekOffset
	 *            -1:上周 0:本周 1:下周
	 * @param startDate
	 *            哪天算一周的第一天
	 * @return yyyy-MM-dd 格式的日期
	 * @throws ParseException
	 * @
	 */
	public static List<String> getWeekDaysAroundDate(String refDate, int weekOffset, String startDate)
			throws ParseException {
		// 以startDate为一周的第一天
		Calendar c = Calendar.getInstance();
		c.setTime(formatStringToDate(startDate, DATE_FORMAT_YMD));
		int firstDayOfWeek = c.get(Calendar.DAY_OF_WEEK);
		// 获取相应周
		int[] weekAndYear = getWeekAndYear(refDate, weekOffset, firstDayOfWeek);
		// 获取相应周的所有日期
		return getWeekDays(weekAndYear[1], weekAndYear[0], firstDayOfWeek);
	}

	/**
	 * 根据时间点获取时间区间
	 * 
	 * @param hours
	 * @return
	 */
	public static List<String[]> getTimePointsByHour(int[] hours) {
		List<String[]> hourPoints = new ArrayList<String[]>();
		String sbStart = ":00:00";
		String sbEnd = ":59:59";
		for (int i = 0; i < hours.length; i++) {
			String[] times = new String[2];
			times[0] = hours[i] + sbStart;
			times[1] = (hours[(i + 1 + hours.length) % hours.length] - 1) + sbEnd;
			hourPoints.add(times);
		}
		return hourPoints;
	}

	/**
	 * 
	 * 根据指定的日期，增加或者减少天数
	 * 
	 * @param date
	 * @param amount
	 * @return
	 */
	public static Date addDays(Date date, int amount) {
		return add(date, Calendar.DAY_OF_MONTH, amount);
	}

	/**
	 * 根据指定的日期，类型，增加或减少数量
	 * 
	 * @param date
	 * @param calendarField
	 * @param amount
	 * @return
	 */
	public static Date add(Date date, int calendarField, int amount) {
		if (date == null) {
			throw new IllegalArgumentException("The date must not be null");
		}
		Calendar c = Calendar.getInstance();
		c.setTime(date);
		c.add(calendarField, amount);
		return c.getTime();
	}

	/**
	 * 获取当前日期的最大日期 时间2014-12-21 23:59:59
	 * 
	 * @return
	 */
	public static Date getCurDateWithMaxTime() {
		Calendar c = Calendar.getInstance();
		c.set(Calendar.HOUR_OF_DAY, 23);
		c.set(Calendar.MINUTE, 59);
		c.set(Calendar.SECOND, 59);
		return c.getTime();
	}

	/**
	 * 获取当前日期的最小日期时间 2014-12-21 00:00:00
	 * 
	 * @return
	 */
	public static Date getCurDateWithMinTime() {
		Calendar c = Calendar.getInstance();
		c.set(Calendar.HOUR_OF_DAY, 0);
		c.set(Calendar.MINUTE, 0);
		c.set(Calendar.SECOND, 0);
		c.set(Calendar.MILLISECOND, 0);
		return c.getTime();
	}
	/**
	 * 取现在时间字符串 格式 201904041322
	 * @author MRC
	 * @date 2019年4月4日下午1:23:05
	 * @return
	 */
	public static String getNowDatetoString(){
		Date currentTime = new Date();  
	    SimpleDateFormat formatter = new SimpleDateFormat("yyyyMMddHHmm");  
	    String dateString = formatter.format(currentTime);  
	    return dateString; 
	}
	
	/**
	 * 获取当前日期，精确到日
	 * @author Fujing
	 * @date 2019年4月11日 下午3:57:34
	 * @return Date
	 */
	public static Date getTodayDate(){
		Date currentTime = new Date();
		SimpleDateFormat formatter = new SimpleDateFormat("yyyy-MM-dd");
		String dateString = formatter.format(currentTime);
		return formatStringToDate(dateString, DateUtils.DATE_FORMAT_YMD);
	}
	
	/**
	 * 获取昨日日期
	 * @author Fujing
	 * @date 2019年4月19日 上午9:15:56
	 * @return String
	 */
	public static String getYesterdayDate(){
		//实例化当天的日期
        Date today = new Date();
        //用当天的日期减去昨天的日期
        Date yesterdayDate = new Date(today.getTime()-86400000L);
        String yesterday = new SimpleDateFormat("yyyy-MM-dd").format(yesterdayDate);
        return yesterday;
	}
	
	/**
	 * 获取指定日期相差i天的日期
	 * @author Fujing
	 * @date 2019年4月19日 下午3:36:12
	 * @param date
	 * @param i		//相差天数
	 * @param format		//返回格式
	 * @return String
	 */
	public static String getDateString(Date date, int i, String format){
		Calendar calendar = Calendar.getInstance();
		//今天
		System.out.println(calendar.getTime());
		//10天前
		calendar.add(Calendar.DATE, i);
		System.out.println(calendar.getTime());
		SimpleDateFormat sdf = new SimpleDateFormat(format);
		return sdf.format(calendar.getTime());
	}
	
	public static void main(String[] args){
		
		Date end = DateUtils.getCurDateWithMinTime();
		Date start = DateUtils.addDays(end, -7);
		
		System.out.println(end);
		System.out.println(start);
		
		
	}
	
}
